package com.hainiu.cat.interview.juc;

import lombok.Data;
import lombok.ToString;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.RandomUtils;
import sun.misc.Unsafe;

import java.lang.reflect.Field;
import java.util.UUID;
import java.util.concurrent.*;
import java.util.stream.Stream;

/**
 * create by biji.zhao on 2021/6/30
 */
public class ThreadModel {

    private static void threadPool() {
        /**
         * 等待队列 BlockingQueue，任务可以储存在任务队列中等待被执行(执行的是FIFIO原则（先进先出）
         *
         * 拒绝策略 RejectedExecutionHandler 在任务满了之后，拒绝执行某些任务
         *
         * 1、空闲核心线程不足，则将任务放入队列等到执行
         * 2、如果队列放不下，则创建非核心线程执行任务
         * 3、如果还是无法执行任务，则使用指定的拒绝策略
         *
         * ThreadPoolExecutor.AbortPolicy(): 不执行新任务，直接抛出异常，提示线程池已满
         * ThreadPoolExecutor.DisCardPolicy()：不执行新任务，也不抛出异常
         * ThreadPoolExecutor.DisCardOldSetPolicy()：将消息队列中的第一个任务替换为当前新进来的任务执行
         * ThreadPoolExecutor.CallerRunsPolicy()：直接调用execute来执行当前任务
         *
         */
        ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(10, 20, 5, TimeUnit.SECONDS, new LinkedBlockingQueue<>(),
                r -> {
                    Thread thread = new Thread();
                    thread.setName("111");
                    thread.setUncaughtExceptionHandler((t, e) -> {
                        // 异常捕获的回调
                    });
                    return thread;
                }, (r, executor) -> new ThreadPoolExecutor.AbortPolicy());
        // 回收核心线程
        poolExecutor.allowCoreThreadTimeOut(true);

        poolExecutor.execute(() -> {

        });

        Stream.of(Thread.State.values()).forEach(e -> System.out.println(e.name()));


        poolExecutor.shutdown();
        poolExecutor.shutdownNow();


        /**
         * new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>())
         * 没有核心线程，非核心线程为int最大
         * 适用于耗时少，任务量大的情况
         */
        ExecutorService executorService = Executors.newCachedThreadPool();
        executorService.submit(() -> {

        });

        /**
         * 周期执行
         *
         */
        ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(10);
        scheduledExecutorService.schedule(() -> System.out.println("we are execute"),2, TimeUnit.SECONDS);


        /**
         * scheduleAtFixedRate并非按照指定的period、delay周期性执行
         * 下一次任务的开始时间取决于前一次任务何时结束，如果前一次任务的执行时间超过period，那么下一次任务在前一次任务执行结束后执行
         */
        scheduledExecutorService.scheduleAtFixedRate(() -> {
            System.out.println("we are execute");
            System.out.println("we are execute");
        }, 1000, 1000, TimeUnit.MICROSECONDS);


        /**
         *   return new ThreadPoolExecutor(nThreads, nThreads,  0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
         *   定长线程池,没有非核心线程
         */
        ExecutorService fixedThreadPool = Executors.newFixedThreadPool(10);

        /**
         * JVM会调用dispatchUncaughtException方法分发处理线程执行中未被捕获的异常，
         * submit 会吞掉异常
         *
         */
        Future<?> submit = fixedThreadPool.submit(() -> {

        });

        fixedThreadPool.execute(() -> {

        });



    }

    private static void atomic() {
        try {
            Field f = Unsafe.class.getDeclaredField("theUnsafe");
            f.setAccessible(true);
            Unsafe unsafe = (Unsafe) f.get(null);
            TestInstance o = (TestInstance)unsafe.allocateInstance(TestInstance.class);

            o.setName("1");
            System.out.println(o);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
//        atomic();
//        Properties properties = System.getProperties();
//        System.out.println(properties);

//        Stream.of(Thread.State.values()).forEach(e -> System.out.println(e.name()));

//        System.out.println(RandomUUIDUtil);
        System.out.println(UUID.randomUUID().toString().replaceAll("-", ""));

    }

    private static void testCountDownLatch() {
        CountDownLatch latch = new CountDownLatch(4);
    }
}

@ToString
@Data
class TestInstance {
    String name;
}
